using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;

namespace RStein.Posterous.API
{
    internal abstract class EntityWithClientStateBase<TDerived> :  ObjectWithId<TDerived>, IEntityWithClientState
                           where TDerived : class
    {
        #region private variables
        private Dictionary<PosterousEntityState, Action> m_saveActions;
        #endregion private variables

        #region constructors
        protected EntityWithClientStateBase(int? id, PosterousEntityState origState) : base(id)
        {
            State = origState;
            m_saveActions = new Dictionary<PosterousEntityState, Action>
                              {
                                  {PosterousEntityState.New, SaveNew},
                                  {PosterousEntityState.Updated, SaveUpdated}
                                  
                              };
        }

        protected EntityWithClientStateBase(PosterousEntityState origState) : this(null, origState)
        {


        }
        
        #endregion constructors
        
        #region properties
        public bool SuppressChanges
        {
            get; 
            set;
        }
        #endregion properties

        #region Implementation of IEntityWithClientState

        public PosterousEntityState State
        {
            get; 
            private set;
        }

        public virtual void SaveChanges()
        {
            Action saveAction = null;

            if (!m_saveActions.TryGetValue(State, out saveAction))
            {
                return;                
            }
            
            saveAction();
            State = PosterousEntityState.Loaded;
            OnSaveChangesCompleted(new EventArgsValue<bool>(true, null));
        }

        public virtual void SaveChangesAsync()
        {
            Action<Exception> exchandler = e =>
            {
                new PosterousException(GlobalConstants.ASYNC_EXCEPTION_TEXT, e);
                OnSaveChangesCompleted(new EventArgsValue<Boolean>(false , e));
            };

            AsyncHelper.RunDelegateAsync((Action) SaveChanges, exchandler, null);             
        }

        public event EventHandler<EventArgsValue<bool>> SaveChangesCompleted;
        #endregion Implementation of IEntityWithClientState

        protected virtual void OnSaveChangesCompleted(EventArgsValue<bool> e)
        {
            EventHandler<EventArgsValue<bool>> handler = SaveChangesCompleted;
            if (handler != null)
            {
                Thread.CurrentThread.GetCurrentSynchronizationContext().Post(o => handler(this, e), null);
            }
        }

        #region methods

        protected abstract void SaveUpdated();

        protected abstract void SaveNew();
        
        
        internal protected virtual void SetDirty()
        {
            if (SuppressChanges)
            {
                return;
            }

            if (State == PosterousEntityState.Loaded)
            {
                State = PosterousEntityState.Updated;    
            }
            
        }

        protected virtual void SetLoaded()
        {
            Debug.Assert(State != PosterousEntityState.New);

            State = PosterousEntityState.Loaded;
        }

        #endregion methods
    }
}